package org.tlang.ast.list.statement;

import org.tlang.ast.AST;
import org.tlang.ast.ASTList;
import org.tlang.context.TypeTable;
import org.tlang.context.ValueTable;
import org.tlang.exception.EvalException;
import org.tlang.exception.TypeException;
import org.tlang.type.BoolType;
import org.tlang.type.Type;
import org.tlang.type.VoidType;

import java.util.List;

public class WhileStatement extends ASTList {
    public WhileStatement(List<AST> children) {
        super(children);
    }

    public AST condition() {
        return child(0);
    }

    public AST block() {
        return child(1);
    }

    @Override
    public String toString() {
        return "(while " + condition() + " " + block() + ")";
    }

    @Override
    public Type typeCheck(TypeTable typeTable) throws TypeException {
        Type conditionType = condition().typeCheck(typeTable);
        conditionType.assertSubTypeOf(BoolType.BOOL_TYPE, typeTable, this);
        block().typeCheck(typeTable);
        return VoidType.VOID_TYPE;
    }

    @Override
    public Object eval(ValueTable valueTable) {
        Object result = null;
        while (true) {
            Object condition = condition().eval(valueTable);
            if (condition instanceof Boolean) {
                if ((Boolean) condition) {
                    result = block().eval(valueTable);
                    continue;
                }

                return result;
            }

            throw new EvalException("condition expression eval result is not boolean", condition());
        }
    }
}
